using System;
using System.Collections.Generic;
using System.Data;
using FluentNHibernate;
using NHibernate;
using NHibernate.Cfg;

namespace UserManagement.Dal.NH.Mappings
{
    public class SessionSource : ISessionSource
    {
        private readonly NHibernate.ISessionFactory _sessionFactory;
        private readonly Configuration _configuration;

        public SessionSource(PersistenceModel model, Configuration configuration) : this(null, model, configuration)
        {
        }

        public SessionSource(IDictionary<string, string> properties, PersistenceModel model, Configuration configuration)
        {
            if (model == null)
            {
                throw new ArgumentNullException("model");
            }

            if (configuration == null)
            {
                _configuration = new Configuration();
                if (properties == null)
                {
                    _configuration.Configure();
                }
                else
                {
                    _configuration.AddProperties(properties);
                }
            }
            else
            {
                _configuration = configuration;
            }

            Model = model;
            model.Configure(_configuration);

            _sessionFactory = _configuration.BuildSessionFactory();
        }

        public PersistenceModel Model { get; private set; }

        public ISession CreateSession()
        {
            return _sessionFactory.OpenSession();
        }

        public void BuildSchema()
        {
            var session = CreateSession();
            BuildSchema(session);
        }

        public void BuildSchema(ISession session)
        {
            var connection = session.Connection;
            var drops = _configuration.GenerateDropSchemaScript(session.GetSessionImplementation().Factory.Dialect);
            ExecuteScripts(drops, connection);

            var scripts = _configuration.GenerateSchemaCreationScript(session.GetSessionImplementation().Factory.Dialect);
            ExecuteScripts(scripts, connection);
        }

        public Configuration Configuration
        {
            get { return _configuration; }
        }

        public NHibernate.ISessionFactory SessionFactory
        {
            get { return _sessionFactory; }
        }

        private static void ExecuteScripts(IEnumerable<string> scripts, IDbConnection connection)
        {
            foreach (var script in scripts)
            {
                var command = connection.CreateCommand();
                command.CommandText = script;
                command.ExecuteNonQuery();
            }
        }
    }
}